#pragma once

#include <httplib.h>
#include <spdlog/spdlog.h>
#include "../util/server.hh"
#include "../util/response.hh"
#include "../service/community-service.hh"
#include "../util/util.hh"
#include "../util/except.hh"

namespace WordMemory
{
    class CommunityController
    {
    public:
        static void registerBusiness()
        {
            Server::instance().regist<Server::BusType::GET>("/api/community/posts", getCommunityPosts);
            Server::instance().regist<Server::BusType::GET>("/api/community/posts/([0-9]+)", getPostById);
            Server::instance().regist<Server::BusType::POST>("/api/community/posts/([0-9]+)/toggle_like", toggleLikePost);
            Server::instance().regist<Server::BusType::POST>("/api/community/posts/([0-9]+)/share", recordShare);

            spdlog::info("Community controller registered");
        }

    private:
        static void getCommunityPosts(const httplib::Request& req, httplib::Response& res)
        {
            try
            {
                int current_user_id = 0;
                if (req.has_param("user_id")) {
                    try {
                        current_user_id = std::stoi(req.get_param_value("user_id"));
                    }
                    catch (const std::invalid_argument&) {
                        spdlog::warn("getCommunityPosts: Invalid user_id parameter provided.");
                    }
                }

                auto posts = CommunityService::instance().getCommunityPosts(current_user_id);
                Json::Value data(Json::arrayValue);
                for (const auto& post : posts) data.append(post.to_json());
                res.status = 200;
                res.set_content(ResponseMessage::success(data), "application/json");
            }
            catch (const ServiceExcept& e) {
                res.status = 500; res.set_content(ResponseMessage::error(e.what()), "application/json");
                spdlog::error("Service error in getCommunityPosts: {}", e.what());
            }
        }

        static void getPostById(const httplib::Request& req, httplib::Response& res)
        {
            try {
                int post_id = std::stoi(req.matches[1].str());
                int current_user_id = 0;
                if (req.has_param("user_id")) {
                    current_user_id = std::stoi(req.get_param_value("user_id"));
                }

                CommunityPost post = CommunityService::instance().getPostById(post_id, current_user_id);
                res.status = 200;
                res.set_content(ResponseMessage::success(post.to_json()), "application/json");
            }
            catch (const std::invalid_argument& e) {
                res.status = 400; res.set_content(ResponseMessage::error("Invalid post_id format."), "application/json");
            }
            catch (const ServiceExcept& e) {
                res.status = (std::string(e.what()).find("not found") != std::string::npos) ? 404 : 500;
                res.set_content(ResponseMessage::error(e.what()), "application/json");
            }
        }

        static void toggleLikePost(const httplib::Request& req, httplib::Response& res)
        {
            try {
                int post_id = std::stoi(req.matches[1].str());
                Json::Value body = JsonUtil::deserialize(req.body);
                if (!body.isMember("user_id") || !body["user_id"].isInt()) {
                    throw ControllerExcept("user_id (integer) is required in JSON body.");
                }
                int user_id = body["user_id"].asInt();

                bool liked_now = CommunityService::instance().toggleLikePost(post_id, user_id);

                CommunityPost updated_post_stub = CommunityService::instance().getPostById(post_id, user_id); // Fetch fresh counts
                Json::Value response_data;
                response_data["post_id"] = post_id;
                response_data["likes_count"] = updated_post_stub.likes_count;
                response_data["is_liked_by_current_user"] = updated_post_stub.is_liked_by_current_user;


                res.status = 200;
                res.set_content(ResponseMessage::success(response_data), "application/json");
            }
            catch (const std::invalid_argument& e) {
                res.status = 400; res.set_content(ResponseMessage::error("Invalid post_id format or JSON body."), "application/json");
            }
            catch (const UtilExcept& e) {
                res.status = 400; res.set_content(ResponseMessage::error("Invalid JSON: " + std::string(e.what())), "application/json");
            }
            catch (const ControllerExcept& e) {
                res.status = 400; res.set_content(ResponseMessage::error(e.what()), "application/json");
            }
            catch (const ServiceExcept& e) {
                res.status = 500; res.set_content(ResponseMessage::error(e.what()), "application/json");
            }
        }

        static void recordShare(const httplib::Request& req, httplib::Response& res)
        {
            try {
                int post_id = std::stoi(req.matches[1].str());

                CommunityService::instance().incrementShareCount(post_id);

                CommunityPost updated_post_stub = CommunityService::instance().getPostById(post_id, 0);
                Json::Value response_data;
                response_data["post_id"] = post_id;
                response_data["shares_count"] = updated_post_stub.shares_count;

                res.status = 200;
                res.set_content(ResponseMessage::success(response_data), "application/json");
            }
            catch (const std::invalid_argument& e) {
                res.status = 400; res.set_content(ResponseMessage::error("Invalid post_id format."), "application/json");
            }
            catch (const ServiceExcept& e) {
                res.status = 404; res.set_content(ResponseMessage::error(e.what()), "application/json");
            }
        }
    };
}